"""
角色服务层
处理角色相关的业务逻辑
"""
from typing import Dict, Any, Optional, Tuple, List
from fastapi import HTTPException, status

from apps.auth.models.role import Role
from apps.auth.models.permission import Permission
from apps.auth.repositories.role_repository import RoleRepository
from apps.auth.repositories.permission_repository import PermissionRepository


class RoleService:
    """角色服务类"""
    
    @staticmethod
    async def create_role(role_data: Dict[str, Any]) -> Role:
        """
        创建角色
        :param role_data: 角色数据
        :return: 创建的角色实例
        :raises: HTTPException 如果角色标识已存在
        """
        # 检查角色标识是否存在
        if await RoleRepository.exists_by_slug(role_data["slug"]):
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail="角色标识已存在"
            )
        
        # 创建角色
        role = await RoleRepository.create(role_data)
        return role
    
    @staticmethod
    async def get_role_by_id(role_id: int) -> Role:
        """
        通过ID获取角色
        :param role_id: 角色ID
        :return: 角色实例
        :raises: HTTPException 如果角色不存在
        """
        role = await RoleRepository.get_by_id(role_id)
        if not role:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"ID为{role_id}的角色不存在"
            )
        return role
    
    @staticmethod
    async def list_roles(
        page: int = 1, 
        page_size: int = 10,
        search: Optional[str] = None,
    ) -> Tuple[List[Role], int]:
        """
        获取角色列表
        :param page: 页码
        :param page_size: 每页大小
        :param search: 搜索关键词
        :return: 角色列表和总数
        """
        return await RoleRepository.list_roles(page, page_size, search)
    
    @staticmethod
    async def update_role(role_id: int, update_data: Dict[str, Any]) -> Role:
        """
        更新角色信息(部分更新)
        :param role_id: 角色ID
        :param update_data: 更新数据
        :return: 更新后的角色
        :raises: HTTPException 如果角色不存在
        """
        # 获取角色
        role = await RoleService.get_role_by_id(role_id)
        
        # 如果更新数据包含slug，检查是否冲突
        if "slug" in update_data and update_data["slug"] != role.slug:
            if await RoleRepository.exists_by_slug(update_data["slug"]):
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="角色标识已存在"
                )
        
        # 更新角色
        updated_role = await RoleRepository.update(role, update_data)
        return updated_role
    
    @staticmethod
    async def update_role_whole(role_id: int, update_data: Dict[str, Any]) -> Role:
        """
        全量更新角色信息
        :param role_id: 角色ID
        :param update_data: 完整的更新数据
        :return: 更新后的角色
        :raises: HTTPException 如果角色不存在
        """
        # 获取角色
        role = await RoleService.get_role_by_id(role_id)
        
        # 如果更新了标识且标识已存在，则抛出异常
        if update_data["slug"] != role.slug:
            if await RoleRepository.exists_by_slug(update_data["slug"]):
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="角色标识已存在"
                )
        
        # 全量更新角色
        updated_role = await RoleRepository.update_whole(role, update_data)
        return updated_role
    
    @staticmethod
    async def delete_role(role_id: int) -> None:
        """
        软删除角色（逻辑删除）
        :param role_id: 角色ID
        :raises: HTTPException 如果角色不存在
                 HTTPException 如果尝试删除系统角色
        """
        # 检查角色是否存在
        role = await RoleRepository.get_by_id(role_id)
        if not role:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="角色不存在"
            )
        
        # 不允许删除系统角色
        if role.is_system:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="系统角色不允许删除"
            )
        
        # 软删除角色
        await RoleRepository.delete(role)
    
    @staticmethod
    async def hard_delete_role(role_id: int) -> None:
        """
        硬删除角色（物理删除）
        :param role_id: 角色ID
        :raises: HTTPException 如果角色不存在
                 HTTPException 如果尝试删除系统角色
        """
        # 检查角色是否存在
        role = await RoleRepository.get_by_id(role_id)
        if not role:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="角色不存在"
            )
        
        # 不允许删除系统角色
        if role.is_system:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="系统角色不允许删除"
            )
        
        # 硬删除角色
        await RoleRepository.hard_delete(role)
    
    @staticmethod
    async def get_role_permissions(role_id: int) -> List[Permission]:
        """
        获取角色拥有的所有权限
        :param role_id: 角色ID
        :return: 权限列表
        :raises: HTTPException 如果角色不存在
        """
        # 确保角色存在
        await RoleService.get_role_by_id(role_id)
        
        return await RoleRepository.get_role_permissions(role_id)
    
    @staticmethod
    async def assign_permission_to_role(role_id: int, permission_id: int) -> bool:
        """
        为角色分配权限
        :param role_id: 角色ID
        :param permission_id: 权限ID
        :return: 是否分配成功
        :raises: HTTPException 如果角色或权限不存在
        """
        # 确保角色存在
        await RoleService.get_role_by_id(role_id)
        
        # 确保权限存在
        permission = await PermissionRepository.get_by_id(permission_id)
        if not permission:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"ID为{permission_id}的权限不存在"
            )
        
        return await RoleRepository.assign_permission(role_id, permission_id)
    
    @staticmethod
    async def remove_permission_from_role(role_id: int, permission_id: int) -> bool:
        """
        移除角色中的权限
        :param role_id: 角色ID
        :param permission_id: 权限ID
        :return: 是否移除成功
        :raises: HTTPException 如果角色或权限不存在
        """
        # 确保角色存在
        await RoleService.get_role_by_id(role_id)
        
        # 确保权限存在
        permission = await PermissionRepository.get_by_id(permission_id)
        if not permission:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"ID为{permission_id}的权限不存在"
            )
        
        return await RoleRepository.remove_permission(role_id, permission_id)
    
    @staticmethod
    async def update_role_permissions(role_id: int, permission_ids: List[int]) -> int:
        """
        更新角色的权限列表
        :param role_id: 角色ID
        :param permission_ids: 权限ID列表
        :return: 分配的权限数量
        :raises: HTTPException 如果角色不存在或权限不存在
        """
        # 确保角色存在
        await RoleService.get_role_by_id(role_id)
        
        # 清除当前所有权限
        await RoleRepository.clear_permissions(role_id)
        
        # 验证所有权限都存在
        for permission_id in permission_ids:
            if not await PermissionRepository.exists_by_id(permission_id):
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail=f"ID为{permission_id}的权限不存在"
                )
        
        # 批量分配新权限
        assigned_count = 0
        for permission_id in permission_ids:
            success = await RoleRepository.assign_permission(role_id, permission_id)
            if success:
                assigned_count += 1
                
        return assigned_count
    
    @staticmethod
    async def get_role_users(role_id: int) -> List["User"]:
        """
        获取拥有指定角色的所有用户
        :param role_id: 角色ID
        :return: 用户列表
        :raises: HTTPException 如果角色不存在
        """
        # 确保角色存在
        await RoleService.get_role_by_id(role_id)
        
        return await RoleRepository.get_role_users(role_id)
    
    @staticmethod
    async def assign_role_to_user(role_id: int, user_id: int) -> bool:
        """
        为用户分配角色
        :param role_id: 角色ID
        :param user_id: 用户ID
        :return: 是否分配成功
        :raises: HTTPException 如果角色或用户不存在
        """
        # 确保角色存在
        await RoleService.get_role_by_id(role_id)
        
        # 确保用户存在
        from apps.auth.repositories.user_repository import UserRepository
        user = await UserRepository.get_by_id(user_id)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"ID为{user_id}的用户不存在"
            )
        
        return await RoleRepository.assign_user(role_id, user_id)
    
    @staticmethod
    async def remove_role_from_user(role_id: int, user_id: int) -> bool:
        """
        从用户中移除角色
        :param role_id: 角色ID
        :param user_id: 用户ID
        :return: 是否移除成功
        :raises: HTTPException 如果角色或用户不存在
        """
        # 确保角色存在
        await RoleService.get_role_by_id(role_id)
        
        # 确保用户存在
        from apps.auth.repositories.user_repository import UserRepository
        user = await UserRepository.get_by_id(user_id)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"ID为{user_id}的用户不存在"
            )
        
        return await RoleRepository.remove_user(role_id, user_id)
    
    @staticmethod
    async def update_role_users(role_id: int, user_ids: List[int]) -> int:
        """
        更新角色的用户列表
        :param role_id: 角色ID
        :param user_ids: 用户ID列表
        :return: 分配的用户数量
        :raises: HTTPException 如果角色不存在或用户不存在
        """
        # 确保角色存在
        await RoleService.get_role_by_id(role_id)
        
        # 清除当前所有用户的角色关系
        await RoleRepository.clear_users(role_id)
        
        # 验证所有用户都存在
        from apps.auth.repositories.user_repository import UserRepository
        for user_id in user_ids:
            if not await UserRepository.exists_by_id(user_id):
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail=f"ID为{user_id}的用户不存在"
                )
        
        # 批量分配新用户
        assigned_count = 0
        for user_id in user_ids:
            success = await RoleRepository.assign_user(role_id, user_id)
            if success:
                assigned_count += 1
                
        return assigned_count
